#include "calculsoustableau.h"

// constructeur calcule
calcule::calcule(vector<int> *cgh_,int x0_,int x1_,result *resultatfinal_) : cgh(cgh_),x0(x0_),x1(x1_),resultatfinal(resultatfinal_) {}
//tache de calcule
tbb::task* calcule::execute(){
    calculSousTableau (cgh,x0,x1,resultatfinal);
    return NULL;
}

//fonction de calcule du sous tableau
void calcule::calculSousTableau (vector<int> *cgh,int x0,int x1,struct result *resultatfinal){
//declaration des variables
    std::cout<<"declaration variable de la fonction calcul sous tableau"<<endl;
    struct result resultat;
    vector<int> ssum((*cgh).size());
    vector<int> pmax((*cgh).size());
    vector<int> psum((*cgh).size());
    vector<int> smax((*cgh).size());
    vector<int> m((*cgh).size());
    int mmax;
    int y0;
    int y1;
//declaration des pointeurs
    vector<int> *pssum;
    vector<int> *ppmax;
    vector<int> *ppsum;
    vector<int> *psmax;
    vector<int> *pm;
    int *y0_p;
    int *y1_p;
//affectation des pointeurs
    pssum=&ssum;
    ppsum=&psum;
    ppmax=&pmax;
    psmax=&smax;
    pm=&m;
    y0_p=&y0;
    y1_p=&y1;
    //creation objet
    calcule1& calc1 = *new(allocate_child()) calcule1(cgh,ppsum,psmax);
    calcule2& calc2 = *new(allocate_child()) calcule2(cgh,pssum,ppmax);
    set_ref_count(3);
    calculefinal calcf;
//lance un thread pour le calcul de psum smax
    tbb::task::spawn(calc1);
//lance un thread pour le calcul de ssum pmax et attendre la fin calcul psum,ssum,pmax et smax
    tbb::task::spawn_and_wait_for_all(calc2);
    std::cout<<"calcul M"<<endl;
    mmax=calcf.calculM(y0_p,y1_p,cgh,pssum,ppsum,ppmax,psmax,pm);
    std::cout<<"Mise en forme du resultat"<<endl;
    //mise en forme du resultat
    resultat.y0=y0;
    resultat.y1=y1;
    resultat.m=mmax;
    resultat.x0=x0;
    resultat.x1=x1;
//envoi du resultat si resultat plus grand que celui deja presant
    if((*resultatfinal).m<resultat.m){
        *resultatfinal=resultat;

    }
    std::cout<<"resultat x0 = "<<resultat.x0<<" x1 = "<<resultat.x1<<" y0 = "<<resultat.y0<<" y1 = "<<resultat.y1<<" M = "<<resultat.m<<endl;
    std::cout<<"fin sstableau"<<endl;
}

//constructeur de calcule1
calcule1::calcule1( vector<int> *cgh_,vector<int> *psum_,vector<int> *smax_) : cgh(cgh_),psum(psum_),smax(smax_) {}

//tache effectué par calcule1
tbb::task* calcule1::execute() {
            std::cout<<"calcul psum"<<endl;
            calcule1::calc_psum(cgh,psum);
            std::cout<<"calcul smax"<<endl;
            calcule1::calc_smax(psum,smax);
            std::cout<<"fin calcul1"<<endl;
            return NULL;
        }

//calcul ssum la somme des suffixes du tableau cgh
void calcule1::calc_psum(vector<int> *cgh,vector<int> *psum){
    (*psum)[0]=(*cgh)[0];
    std::cout<<"psum(0) = "<<((*psum)[0])<<endl;
    for (int i=1;i<=(*cgh).size()-1;i++){
        (*psum)[i]=(*cgh)[i]+(*psum)[i-1];
        std::cout<<"psum("<<i<<") = "<<((*psum)[i])<<endl;
        }
}

//calcul pmax inscrit la valeur la plus forte rencontré dans un case en lisant ssum de la droite vers la gauche
void calcule1::calc_smax(vector<int> *psum,vector<int> *smax){
    int smmax = (*psum)[(*psum).size()-1];
    //std::cout<<"pmmax = "<<pmmax<<endl;
    for(int i=(*psum).size()-1;i>=0;i--){
        //std::cout<<"ssum("<<i<<") = "<<ssum[i]<<endl;
        if((*psum)[i]>smmax){
            smmax=(*psum)[i];
            //std::cout<<"pmmax = "<<pmmax<<endl;
        }
        (*smax)[i]=smmax;
        std::cout<<"smax("<<i<<") = "<<(*smax)[i]<<endl;
    }
}

//constructeur calcule 2
calcule2::calcule2( vector<int> *cgh_,vector<int> *ssum_,vector<int> *pmax_) : cgh(cgh_),ssum(ssum_),pmax(pmax_){}

//tache effectuer par calcule2
//ici calcule2 va calculer la ssum puis le pmax du cgh donné en entrée
tbb::task* calcule2::execute(){
        std::cout<<"calcul ssum"<<endl;
        calcule2::calc_ssum(cgh,ssum);
        std::cout<<"calcul pmax"<<endl;
        calcule2::calc_pmax(ssum,pmax);
        std::cout<<"fin calcule2"<<endl;
        return NULL;
    }

//calcul psum calcule la somme des prefixes
void calcule2::calc_ssum(vector<int> *cgh,vector<int> *ssum){
    (*ssum)[(*cgh).size()-1]=(*cgh)[(*cgh).size()-1];
    std::cout<<" ssum("<<(*cgh).size()-1<<" = "<<(*ssum)[(*cgh).size()-1]<<endl;
    for(int i=(*cgh).size()-2;i>=0;i--){
        //std::cout<<"i= "<<i<<endl;
        (*ssum)[i]=(*cgh)[i]+(*ssum)[i+1];
        std::cout<<" ssum("<<i<<") = "<<(*ssum)[i]<<endl;
    }
}

//calcul smax inscrit la valeur la plus forte rencontré dans un case en lisant psum de la gauche vers la droite
void calcule2::calc_pmax(vector<int> *ssum,vector<int> *pmax){
    int pmmax=(*ssum)[0];
    //std::cout<<" smmax = "<<smmax<<endl;
    for(int i=0;i<=(*ssum).size()-1;i++){
        //std::cout<<" psum("<<i<<") = "<<psum[i]<<endl;
        if((*ssum)[i]>pmmax){
            pmmax=(*ssum)[i];
            //std::cout<<" smmax = "<<smmax<<endl;
        }
        (*pmax)[i]=pmmax;
        std::cout<<" pmax("<<i<<") = "<<(*pmax)[i]<<endl;
    }

}

//calcul m valeur max du sous tableau optimal de la ligne et sa position dans le tableau cgh
int calculefinal::calculM(int *y0,int *y1,vector<int> *cgh,vector<int> *ssum,vector<int> *psum,vector<int> *pmax,vector<int> *smax,vector<int> *m){
    std::cout<<"debut M"<<endl;
    int mmax;

//calcul du tableau de m
    std::cout<<"calcul du tableau de m"<<endl;
    for(int i=0;i<=(*cgh).size()-1;i++){
        (*m)[i]=(*pmax)[i]+(*smax)[i]-(*psum)[i]-(*ssum)[i]+(*cgh)[i];
        std::cout<<" m("<<i<<") = "<<(*m)[i]<<endl;
    }

//recherche de la valeur de m la plus grande
    std::cout<<"recherche de la valeur de m la plus grande"<<endl;
    mmax=(*m)[1];
    for(int i=1;i<=(*cgh).size()-1;i++){
        if((*m)[i]>mmax){
            mmax=(*m)[i];
        }
    }

//recherche fin de la suite de valeur mmax
    std::cout<<"recherche fin de la suite de valeur mmax"<<endl;
    *y1=(*cgh).size()-1;
    for(int i=1;i<=(*cgh).size()-1;i++){
        if((*m)[i-1]>(*m)[i] && (*m)[i-1]==mmax){
            *y1=i-1;
        }
    }

//recherche du debut de la suite de valeur mmax
    std::cout<<"recherche du debut de la suite de valeur mmax"<<endl;
    *y0=0;
    for(int i=(*cgh).size()-1;i>=1;i--){
        std::cout<<"i = "<<i<<endl;
        if((*m)[i-1]<(*m)[i] && (*m)[i]==mmax){
            *y0=i;
        }
    }

    return mmax;

}
